SublimeText2アドベントカレンダー2012


概要

みんなだいすきSublimeText2、のアドカレ!

http://www.adventar.org/calendars/20


3日目です。

written by @toru_inoue



SublimeText2でのプラグイン作りで、ハマりやすいところについて

つらつら3点ほど、まとめつつ書きます。


以前作り方的に悩んだ部分を纏めたのですが、

http://bit.ly/UaWF0u


身内からも、「羅列してある感じで良くワカんねぇッス!!」とか

「★になれ!! クマと戦え!!」とブワッ(´;ω;`)な感じだったため

Tipsとして転生します。



1.Sublimeの command と python ファイルの連携について

ST2には、command と呼ばれる概念なものがあります。

{"id": "Gradle", "caption": "Build current project", "command": "gbuild" }

この command を実行すると、プラグインフォルダ中の なんちゃら.py の中身が実行される訳なんですが、

実行されるメソッドは、下記のルールさえ守っていれば何でも良いみたいです。


①なんちゃら.pyが存在する

②上記で言う、gbuild を先頭に含んでいるクラス定義がある

ここが一番厄介。


gbuild はもちろんのこと、


gbuildCommand とか

gbuildHyahhar とかでもOK。


さらに、一般的にはclass大文字で始めるんじゃねェの的な意味で、

Gbuild とかもOK。

ただし、途中での大文字の扱いが歪で、


command の呼び出し定義を

"command": "gbuildDependents"

とか書いてしまって、

gbuildDependents

みたいなクラス名で定義しても、command が呼ばれません。


このへんは結構歪で、結局自分は command 定義部分はすべて小文字、

クラス定義側は頭のみ大文字、にしました。

信じてたのに!! 最初の大文字はOKだから信じてたのに!!

はい。駄目です。



③そのclassが sublime_plugin.TextCommand / sublime_plugin.WindowCommand / sublime_plugin.ApplicationCommand のどれかを継承している

微妙に用途が異なるST2プラグイン用のクラスが定義されてるので、継承します。


それぞれの用途については下記参考。

http://www.sublimetext.com/docs/api-reference#sublimeplugin.Plugin


④run メソッドが定義されている

⑤そのメソッドが継承したclass に対応する引数持ってる

ふまえると、上記のcommand gbuild  の定義はこんな感じになります。


import sublime

import sublime_plugin


class Gbuild(sublime_plugin.TextCommand):

  def run (self, edit) :

    # 何か処理



2.いつの間にかショートカットがついてる場合

コレですコレ。

スクリーンショット 2012-12-02 17.21.52.png

前出の command について、ショートカットを設定出来ます。


設定は、プラグインパッケージ内の

Default.sublime-keymap ファイルから行えます。


ただ自分がモロにハマった事象があって、把握までちょっとかかったので共有までに。


・既にショートカットが定義されている command と同じ名前の command を定義してしまうと、

Packageの壁を越えてショートカットマークが勝手に付く


例えば、buid、って名前の command を定義しちゃったとしましょう。

すると、CommandPalette とかに出る訳なんですが、


他のプラグインで build って command が既に定義してあってですね。

しかもショートカットも既に書いてあったんですね。


結果、自分が定義したcommandが表示されるべき箇所にも、ショートカットマークが出ちゃいます。

最初、何故付いたんだろう、なんだろうなーってわからんかったっすわ。


解決策としては、

・command の名前をユニークなものにする

・キーボードショートカットは無かった事にする

などです。

キーボードショートカットを簡単に定義できるのもST2のステキな所! なのですが、


ぶっちゃけCommandPaletteがあるのでもう必要ないんじゃないでしょうか。

ショートカットは簡単に他のとぶつかるし。



3.プラグインから外部プロセスを呼ぶ

いろいろな方法が有るのですが、自分は


subprocess.Popen

を使っています。


こんな感じ。


self.process = subprocess.Popen(shlex.split(self.command.encode('utf8')), stdout=subprocess.PIPE, preexec_fn=os.setsid)

引数には、shlexで文字列をArrayに分割して放り込む、という風にしています。

一応Tipsとしては2つあり、


・stroutの内容を取得するために、PIPEを設定


こうする事で、

self.process.stdout 

関連の標準出力が監視できます。


・このプロセスの処理に時間かかり過ぎたときにkillできるように、preexec_fn=os.setsid を設定


こうする事で、

os.killpg(self.process.pid, signal.SIGTERM)


が通用します。

ほんとは2.7以降ならもっと別の手法が有るっぽいのですが、ST2が使用するのはPython2.6 なので、

涙をのんでこんな所です。



おしまい

こんな所でしょうか。

明日は4日目、 sada hirai さんです。